import { ClearEditorPlugin } from "@lexical/react/LexicalClearEditorPlugin";
import { LexicalComposer } from "@lexical/react/LexicalComposer";
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
import { ContentEditable } from "@lexical/react/LexicalContentEditable";
import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary";
import { HistoryPlugin } from "@lexical/react/LexicalHistoryPlugin";
import { OnChangePlugin } from "@lexical/react/LexicalOnChangePlugin";
import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
import { LabelWithTips } from "@renderer/components/business/label-with-tips";
import { cn } from "@renderer/lib/utils";
import {
  $getRoot,
  type EditorState,
  type LexicalEditor,
  TextNode,
} from "lexical";
import { useCallback, useEffect } from "react";
import { useTranslation } from "react-i18next";
import { textJsonToEditorState } from "../utils";
import { ClearEditorBtn } from "./clear-editor-btn";
import { CustomTextNode } from "./nodes/custom-text-node";
import { VariableValueNode } from "./nodes/variable-value-node";
import { ExternalUpdatePlugin } from "./plugins/external-update-plugin";
import { OnBlurOrFocusPlugin } from "./plugins/on-blur-or-focus-plugin";
import { VariablePlugin } from "./plugins/variable-plugin";

interface PromptEditorProps {
  label: string;
  tips: string;
  isSystemPrompt: boolean;
  wrapperClassName?: string;
  className?: string;
  value: string | null;
  rightNode?: React.ReactNode;
  canReset?: boolean;

  onChange: (value: string) => void;
  onEditorReady?: (editor: LexicalEditor) => void;
}

function EditorSetup({
  onEditorReady,
}: {
  onEditorReady?: (editor: LexicalEditor) => void;
}) {
  const [editor] = useLexicalComposerContext();

  useEffect(() => {
    if (onEditorReady) {
      onEditorReady(editor);
    }
  }, [editor, onEditorReady]);

  return null;
}

export function PromptEditor({
  label,
  tips,
  wrapperClassName,
  className,
  value,
  rightNode,
  canReset,
  isSystemPrompt,
  onChange,
  onEditorReady,
}: PromptEditorProps) {
  const { t } = useTranslation("translation", {
    keyPrefix: "chat.tool-bar.parameters.prompt-editor",
  });

  const initialConfig = {
    namespace: "prompt-editor",
    nodes: [
      VariableValueNode,
      CustomTextNode,
      {
        replace: TextNode,
        with: (node: TextNode) => new CustomTextNode(node.__text),
      },
    ],
    editorState: textJsonToEditorState(value),
    onError: (error: Error) => {
      throw error;
    },
  };

  const handleEditorStateChange = useCallback(
    (editorState: EditorState) => {
      const text = editorState.read(() => {
        return $getRoot()
          .getChildren()
          .map((p) => p.getTextContent())
          .join("\n");
      });

      onChange(text);
    },
    [onChange],
  );

  return (
    <LexicalComposer initialConfig={{ ...initialConfig }}>
      <div className="flex flex-col gap-y-2">
        <div className="flex items-center justify-between gap-2">
          <LabelWithTips label={label} tips={tips} tooltipPlacement="right" />
          <div className="flex flex-row gap-x-2">
            {rightNode}
            {canReset && <ClearEditorBtn title={t("reset")} />}
          </div>
        </div>

        <div
          className={cn(
            "h-full rounded-[10px] bg-setting px-2.5 py-2",
            "field-sizing-content max-h-96 min-h-16 w-full min-w-0 rounded-lg border border-input px-2.5 py-2 shadow-xs outline-hidden transition duration-200",
            "focus-within:border-ring/70 focus-within:ring-3 focus-within:ring-ring/20 hover:border-current/10 focus-within:hover:border-ring/70",
            wrapperClassName,
          )}
        >
          <RichTextPlugin
            contentEditable={
              <ContentEditable
                className={cn(
                  "h-full flex-1 text-fg text-sm outline-none",
                  className,
                )}
              />
            }
            ErrorBoundary={LexicalErrorBoundary}
          />
          <EditorSetup onEditorReady={onEditorReady} />
          <ExternalUpdatePlugin />
          <VariablePlugin isSystemPrompt={isSystemPrompt} />
          <OnBlurOrFocusPlugin />
          <HistoryPlugin />
          <ClearEditorPlugin />
          <OnChangePlugin
            ignoreSelectionChange
            onChange={handleEditorStateChange}
          />
        </div>
      </div>
    </LexicalComposer>
  );
}
